package org.sixtynine.stock.controller;

import java.util.List;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import net.tanesha.recaptcha.ReCaptchaImpl;

import org.sixtynine.stock.Constants;
import org.sixtynine.stock.Constants.CommonData;
import org.sixtynine.stock.dto.GridPramDTO;
import org.sixtynine.stock.dto.Page;
import org.sixtynine.stock.entity.BaseEntity;
import org.sixtynine.stock.entity.User;
import org.sixtynine.stock.entity.UserCategory;
import org.sixtynine.stock.model.LoadingSearchCriteria;
import org.sixtynine.stock.service.GenericService;
import org.sixtynine.stock.service.UserCategoryService;
import org.sixtynine.stock.service.UserService;
import org.sixtynine.stock.service.content.DataManagerService;
import org.sixtynine.stock.util.SecurityUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;

/**
 * @author Thilan
 * 
 *         this class use to add , edit and delete user data
 * 
 */

@Controller
@SessionAttributes
public class UserRegistrtionController extends AbstractFrontController {

	/** TODO configure */
	private int RECORDS_PER_PAGE = 10;

	@Autowired
	private GenericService genericService;

	@Autowired
	ReCaptchaImpl reCaptcha;

	@Autowired
	DataManagerService dataManagerService;

	@Autowired
	UserService userService;

	@Autowired
	UserCategoryService userCategoryService;

	@RequestMapping(value = "/user/search")
	public ModelAndView search(@ModelAttribute LoadingSearchCriteria criteria) {
		ModelAndView modelAndView = new ModelAndView("user/list");
		loadData(1, -1, criteria.getUserCategoryId(), modelAndView, criteria);

		return modelAndView;
	}

	/*
	 * This method use to set user adding view
	 */
	@RequestMapping(value = "/user/add")
	public ModelAndView addUser() {
		ModelAndView modelAndView = new ModelAndView("user/add");
		modelAndView.addObject("user", new User());

		return modelAndView;
	}

	@RequestMapping(value = "/admin/user/add")
	public ModelAndView addUserFromAdmin() {
		ModelAndView modelAndView = new ModelAndView("/admin/user/add");

		List<BaseEntity> userCategories = dataManagerService
				.getData(CommonData.USER_CATEGORY.toString());
		modelAndView.addObject("userCategoryMap", userCategories);

		modelAndView.addObject("user", new User());

		return modelAndView;
	}

	/*
	 * This method use to save user category
	 */
	@RequestMapping(value = "/admin/user/add/process")
	public ModelAndView addingUserFromUser(@ModelAttribute @Valid User user,
			BindingResult result, ServletRequest servletRequest,
			SessionStatus sessionStatus, Model model) {
		ModelAndView modelAndView = null;

		String message = null;
		if (userService.isUserExist(user.getUserName())) {
			modelAndView = new ModelAndView("/admin/user/add");
			List<BaseEntity> userCategories = dataManagerService
					.getData(CommonData.USER_CATEGORY.toString());
			modelAndView.addObject("userCategoryMap", userCategories);
			message = "User name already exsist";
			modelAndView.addObject("message", message);
			return modelAndView;
		}
		if (userService.isEmailExist(user.getEmail())) {
			modelAndView = new ModelAndView("/admin/user/add");
			List<BaseEntity> userCategories = dataManagerService
					.getData(CommonData.USER_CATEGORY.toString());
			modelAndView.addObject("userCategoryMap", userCategories);
			message = "Email already exsist";
			modelAndView.addObject("message", message);
			return modelAndView;
		}

		if (!result.hasErrors()) { // && reCaptchaResponse.isValid()
			user.setPassword(SecurityUtil.encrypt(user.getPassword()));
			genericService.saveOrUpdate(user);
			modelAndView = new ModelAndView("/admin/user/list");
		} else {
			modelAndView = new ModelAndView("/admin/user/add");
			modelAndView.addObject("user", new User());
		}

		loadData(1, -1, -1, modelAndView, null);
		return modelAndView;

	}

	/*
	 * This method use to save user category
	 */
	@RequestMapping(value = "/user/add/process")
	public ModelAndView addingUser(@ModelAttribute @Valid User user,
			BindingResult result, ServletRequest servletRequest,
			SessionStatus sessionStatus, Model model) {
		ModelAndView modelAndView = null;

		String message = null;
		if (userService.isUserExist(user.getUserName())) {
			modelAndView = new ModelAndView("user/add");
			List<BaseEntity> userCategories = dataManagerService
					.getData(CommonData.USER_CATEGORY.toString());
			modelAndView.addObject("userCategoryMap", userCategories);
			message = "User name already exsist";
			modelAndView.addObject("message", message);
			showBannar(modelAndView);
			return modelAndView;
		}
		if (userService.isEmailExist(user.getEmail())) {
			modelAndView = new ModelAndView("user/add");
			List<BaseEntity> userCategories = dataManagerService
					.getData(CommonData.USER_CATEGORY.toString());
			modelAndView.addObject("userCategoryMap", userCategories);
			message = "Email already exsist";
			modelAndView.addObject("message", message);
			showBannar(modelAndView);
			return modelAndView;
		}
		if (!result.hasErrors()) { // && reCaptchaResponse.isValid()
			user.setPassword(SecurityUtil.encrypt(user.getPassword()));
			UserCategory usercategory = userCategoryService
					.findUserCategory(Constants.UR_FREE_USER);
			user.setUserCategory(usercategory);
			genericService.saveOrUpdate(user);
			modelAndView = new ModelAndView("home");
			showBannar(modelAndView);

		} else {
			modelAndView = new ModelAndView("user/add");
			modelAndView.addObject("user", new User());
			showBannar(modelAndView);
		}

		return modelAndView;

	}

	/*
	 * This method use to view list of users
	 */
	@RequestMapping(value = "/admin/user/list")
	public ModelAndView listOfTeams(
			@RequestParam(value = "page", required = false) Integer page,
			@RequestParam(value = "totalRecords", required = false) Integer totalRecords) {
		ModelAndView modelAndView = new ModelAndView("/admin/user/list");
		loadData(page, totalRecords, -1, modelAndView, null);

		return modelAndView;
	}

	/**
	 * load data
	 * 
	 * @param page
	 * @param totalRecords
	 * @param companyId
	 * @param fromDate
	 * @param toDate
	 * @param modelAndView
	 */
	private void loadData(Integer page, Integer totalRecords,
			int userCategoryId, ModelAndView modelAndView,
			LoadingSearchCriteria criteria) {
		GridPramDTO gridPramDTO = new GridPramDTO();
		gridPramDTO.setRows(RECORDS_PER_PAGE);
		if (page != null) {
			gridPramDTO.setPage(page);
		} else {
			gridPramDTO.setPage(1);
		}
		if (totalRecords != null) {
			gridPramDTO._setTotalNumberOfRecords(totalRecords);
		}

		Page<User> userPage = userService.searchUser(userCategoryId,
				gridPramDTO);
		modelAndView.addObject("userPage", userPage);

		List<BaseEntity> userCategories = dataManagerService
				.getData(CommonData.USER_CATEGORY.toString());
		modelAndView.addObject("userCategoryMap", userCategories);

		if (criteria == null) {
			criteria = new LoadingSearchCriteria();

			criteria.setUserCategoryId(userCategoryId);

		}
		modelAndView.addObject("criteria", criteria);

	}

	/*
	 * This method use to set user data into edit view
	 */
	@RequestMapping(value = "/user/edit/{id}", method = RequestMethod.GET)
	public ModelAndView editUser(HttpServletRequest request,
			@PathVariable Integer id) {
		ModelAndView modelAndView = null;
		if (!isUserLogged(request)) {
			modelAndView = new ModelAndView("/login/login");
			modelAndView.addObject("registedUser", new User());
			return modelAndView;
		}
		modelAndView = new ModelAndView("/user/edit");
		BaseEntity user = genericService.findById(id, User.class);
		modelAndView.addObject("user", user);
		List<BaseEntity> userCategories = genericService
				.findAll(UserCategory.class);
		modelAndView.addObject("userCategoryMap", userCategories);
		modelAndView.addObject("userLogged", true);
		showBannar(modelAndView);

		return modelAndView;
	}

	/*
	 * This method use to set user data into edit view from admin
	 */
	@RequestMapping(value = "/admin/user/edit/{id}", method = RequestMethod.GET)
	public ModelAndView editUserFromAdmin(HttpServletRequest request,
			@PathVariable Integer id) {
		ModelAndView modelAndView = null;
		if (!isUserLogged(request)) {
			modelAndView = new ModelAndView("/login/login");
			modelAndView.addObject("registedUser", new User());
			return modelAndView;
		}
		modelAndView = new ModelAndView("/admin/user/edit");
		BaseEntity user = genericService.findById(id, User.class);
		modelAndView.addObject("user", user);
		List<BaseEntity> userCategories = genericService
				.findAll(UserCategory.class);
		modelAndView.addObject("userCategoryMap", userCategories);
		modelAndView.addObject("userLogged", true);

		return modelAndView;
	}

	/*
	 * This method use to update user
	 */
	@RequestMapping(value = "/user/edit/{id}", method = RequestMethod.POST)
	public ModelAndView edditingUser(@ModelAttribute @Valid User user,
			BindingResult result, @PathVariable Integer id) {

		ModelAndView modelAndView = null;
		if (!result.hasErrors()) {
			user.setPassword(SecurityUtil.encrypt(user.getPassword()));
			genericService.saveOrUpdate(user);
			modelAndView = new ModelAndView("/myaccount/main");

			User editedUser = (User) genericService.findById(user.getId(),
					User.class);
			modelAndView.addObject("logedUser", editedUser);

			loadData(1, -1, user.getUserCategory().getId(), modelAndView, null);
			showBannar(modelAndView);
			String message = "Successfully edited.";
			modelAndView.addObject("message", message);

		} else {

			modelAndView = new ModelAndView("/user/edit");
			showBannar(modelAndView);
		}

		loadData(1, -1, user.getUserCategory().getId(), modelAndView, null);
		return modelAndView;
	}

	/*
	 * This method use to update user from backend
	 */
	@RequestMapping(value = "/admin/user/edit/{id}", method = RequestMethod.POST)
	public ModelAndView edditingUserFromAdmin(@ModelAttribute @Valid User user,
			BindingResult result, @PathVariable Integer id) {

		ModelAndView modelAndView = null;
		if (!result.hasErrors()) {
			user.setPassword(SecurityUtil.encrypt(user.getPassword()));
			genericService.saveOrUpdate(user);
			modelAndView = new ModelAndView("/admin/user/list");

			List<BaseEntity> users = genericService.findAll(User.class);
			modelAndView.addObject("users", users);

			loadData(1, -1, user.getUserCategory().getId(), modelAndView, null);

			String message = "User was successfully edited.";
			modelAndView.addObject("message", message);

		} else {
			modelAndView = new ModelAndView("/user/edit");

		}

		loadData(1, -1, user.getUserCategory().getId(), modelAndView, null);
		return modelAndView;
	}

	/*
	 * This method use to delete user.
	 */
	@RequestMapping(value = "/admin/user/delete/{id}", method = RequestMethod.GET)
	public ModelAndView deleteUser(@PathVariable Integer id,
			HttpServletRequest request) {

		ModelAndView modelAndView = null;
		if (!isUserLogged(request)) {
			modelAndView = new ModelAndView("/login/login");
			modelAndView.addObject("registedUser", new User());
			return modelAndView;
		}

		genericService.delete(id, User.class);
		modelAndView = new ModelAndView("/admin/user/list");

		loadData(1, -1, -1, modelAndView, null);

		List<BaseEntity> users = genericService.findAll(User.class);
		modelAndView.addObject("users", users);
		String message = "User successfully deleted.";
		modelAndView.addObject("message", message);
		return modelAndView;
	}

}
